﻿#pragma once

#include "geom_curve.h"

namespace CAGD
{

/**
 * 贝塞尔曲线.
 */
template <int Dim> class GeomPowerCurveDim : public GeomCurveDim<Dim>
{
  public:
    /**
     * @brief 基本构造函数.
     * @param cpts
     * @see
     */
    GeomPowerCurveDim(const std::vector<BPntN<Dim>> &cpts) : m_cpts(cpts)
    {
    }

    /**
     * @brief 返回控制点.
     * @return
     * @see
     */
    const std::vector<BPntN<Dim>> &Poles() const
    {
        return m_cpts;
    }

    /**
     * @brief 设置控制点.
     * @param cpts
     * @see
     */
    void SetPoles(const std::vector<BPntN<Dim>> &cpts)
    {
        m_cpts = cpts;
    }

    /**
     * @brief 控制点数量.
     * @return
     * @see
     */
    int NbPoles() const
    {
        return m_cpts.size();
    }

    /**
     * @brief 次数.
     * @return
     * @see
     */
    int Degree() const
    {
        return m_cpts.size() - 1;
    }

    /**
     * @brief 起始参数.
     * @return
     * @see
     */
    double FirstParameter() const override
    {
        return 0.0;
    }

    /**
     * @brief 终止参数.
     * @return
     * @see
     */
    double LastParameter() const override
    {
        return 1.0;
    }

    /**
     * @brief 取值函数.
     * @param t
     * @param P
     * @see
     */
    void D0(double t, BPntN<Dim> &P) const override
    {
        int n = m_cpts.size();
        P = m_cpts.back();
        for (int i = n; i > 0; i--)
            P = P * t + m_cpts[i - 1];
    }

    /**
     * @brief 求切向.
     * @param t
     * @param P
     * @param V1
     * @see
     */
    void D1(double t, BPntN<Dim> &P, BVecN<Dim> &V1) const override
    {
        D0(t, P);

        int n = m_cpts.size();
        V1 = m_cpts.back() * n;
        for (int i = n - 1; i > 0; i--)
            V1 = V1 * t + m_cpts[i - 1] * i;
    }

    /**
     * @brief 求 2 阶导.
     * @param t
     * @param P
     * @param V1
     * @param V2
     * @see
     */
    void D2(double t, BPntN<Dim> &P, BVecN<Dim> &V1, BVecN<Dim> &V2) const override
    {
        D1(t, P, V1);

        int n = m_cpts.size();
        V2 = m_cpts.back() * n * (n - 1);
        for (int i = n - 2; i > 0; i--)
            V2 = V2 * t + m_cpts[i - 1] * i * (i - 1);
    }

    /**
     * @brief 求 n 阶导.
     * @param N
     * @param t
     * @param P
     * @param V
     * @see
     */
    void DN(int N, double t, BPntN<Dim> &P, std::vector<BVecN<Dim>> &V) const override
    {
        D0(t, P);

        int n = m_cpts.size();
        for (int d = 1; d < N; d++)
        {
            auto V0 = m_cpts.back() * permutation(n, d);
            for (int i = n - d; i > 0; i--)
                V0 = V0 * t + m_cpts[i - 1] * permutation(i, d);
            V.push_back(V0);
        }
    }

    /**
     * @brief 引用必要的控制点.
     * @return
     * @see
     */
    std::vector<BPntN<Dim> *> MakeReference() override
    {
        std::vector<BPntN<Dim> *> reference;
        for (int i = 0; i < m_cpts.size(); i++)
            reference.push_back(&m_cpts[i]);
        return reference;
    }

  protected:
    std::vector<BPntN<Dim>> m_cpts;
};

using Geom2dPowerCurve = GeomPowerCurveDim<2>;
using GeomPowerCurve = GeomPowerCurveDim<3>;

} // namespace CAGD
